<!-- 监听上下左右按键和滑动 -->

<template>
  <div ref="box" tabindex="0" class="focus:border-none outline-none" @focus="isFocus = true" @blur="isFocus = false">
    <slot :focus="isFocus" />
  </div>
</template>

<script lang="ts" setup>
const box = ref<HTMLElement>()
const isFocus = ref(false)
const props = withDefaults(
  defineProps<{
    shortest: number // 最短距离
    useMoveEvent?: boolean // 滑动的时候多次触发
    useKbd?: 'keyup' | 'keydown' // 监听键盘
  }>(),
  {
    shortest: 50,
  },
)
const emits = defineEmits(['right', 'left', 'top', 'bottom', 'touch'])

onMounted(() => {
  let isMove = false
  let startX = 0
  let startY = 0
  let distanceX = 0
  let distanceY = 0
  const dom = box.value as HTMLElement

  const event = (eventsName: 'left' | 'bottom' | 'right' | 'top') => {
    emits(eventsName)
    emits('touch', eventsName)
  }

  const eventOver = () => {
    const absX = Math.abs(distanceX)
    const absY = Math.abs(distanceY)
    const absMin = props.shortest
    if (absX > absMin || absY > absMin) {
      startX += distanceX
      startY += distanceY
      let eventsName: 'left' | 'bottom' | 'right' | 'top'
      if (absX > absY) {
        // 横向
        if (distanceX > 0) {
          eventsName = 'right'
        } else {
          eventsName = 'left'
        }
      } else {
        if (distanceY > 0) {
          eventsName = 'bottom'
        } else {
          eventsName = 'top'
        }
      }
      event(eventsName)
    }
    isMove = false
  }

  dom.addEventListener('touchstart', function (e) {
    startX = e.touches[0].clientX
    startY = e.touches[0].clientY
  })
  dom.addEventListener('touchmove', function (e) {
    e.preventDefault()
    isMove = true
    const moveX = e.touches[0].clientX
    const moveY = e.touches[0].clientY
    distanceX = moveX - startX
    distanceY = moveY - startY
    if (props.useMoveEvent) {
      eventOver()
    }
  })
  dom.addEventListener('touchend', function (e) {
    isMove && eventOver()
  })

  function listener({ key, ctrlKey, altKey, shiftKey }: KeyboardEvent) {
    if (ctrlKey || altKey || shiftKey) return
    switch (key) {
      case 'w':
      case 'ArrowUp':
        return event('top')
      case 'd':
      case 'ArrowRight':
        return event('right')
      case 's':
      case 'ArrowDown':
        return event('bottom')
      case 'a':
      case 'ArrowLeft':
        return event('left')
    }
  }
  watch(
    () => props.useKbd,
    (value) => {
      const listeners: ('keyup' | 'keydown')[] = ['keyup', 'keydown']
      listeners.forEach((name) => {
        // 把之前的注销掉 ！！！
        dom.removeEventListener(name, listener)
      })
      if (value) dom.addEventListener(value, listener)
    },
    { immediate: true },
  )
})
</script>
